package com.yvan.leto.server.security;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.yvan.leto.server.utils.HttpUtil;
import org.joda.time.DateTime;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.Map;

public class JwtHelper {
    private static final String AGENT_ID = "a";
    private static final String TOKEN_VERSION = "v";
    private static final String ROLE = "r";

    public static final String AUTH_HEADER_NAME = "Authorization";
    public static final String AUTH_COOKIE_NAME = "auth";

    //头部
    private static final Map<String, Object> HEADER = new ImmutableMap.Builder<String, Object>()
            .build();

    public static boolean verify(String secret) {
        return verify(getAuthHeader(HttpUtil.currentRequest()), secret);
    }

    /**
     * 校验 jwtToken 是否正确
     */
    public static boolean verify(String jwtToken, String secret) {
        try {
            Algorithm algorithm = null;
            try {
                algorithm = Algorithm.HMAC256(secret);
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
            JWTVerifier verifier = JWT.require(algorithm)
                    .build();
            verifier.verify(jwtToken);
            return true;

        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 校验 jwtToken 是否正确
     */
    public static boolean verify(String jwtToken, String loginName, Long tokenVersion, String secret) {
        try {
            Algorithm algorithm = null;
            try {
                algorithm = Algorithm.HMAC256(secret);
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim(AGENT_ID, loginName)
                    .withClaim(TOKEN_VERSION, tokenVersion)
                    .build();
            verifier.verify(jwtToken);
            return true;

        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获得 agentId
     */
    public static String getLoginName(String token) {
        Map<String, Claim> m = JWT.decode(token).getClaims();
        return m.get(AGENT_ID).asString();
    }

    /**
     * 获取当前请求的 agentId
     */
    public static String getLoginName() {
        return getLoginName(getAuthHeader(HttpUtil.currentRequest()));
    }

    /**
     * 获得 tokenVersion
     */
    public static Integer getTokenVersion(String token) {
        Map<String, Claim> m = JWT.decode(token).getClaims();
        return m.get(TOKEN_VERSION).asInt();
    }

    /**
     * 获得 ROLE
     */
    public static String getRole(String token) {
        Map<String, Claim> m = JWT.decode(token).getClaims();
        return m.get(ROLE).asString();
    }

    /**
     * 获取授权过期时间
     */
    public static DateTime getExpireTime(String token) {
        return new DateTime(JWT.decode(token).getExpiresAt().getTime());
    }

    public static boolean isLogined() {
        return (getAuthHeader(HttpUtil.currentRequest()) != null);
    }

    public static String getAuthHeader(ServletRequest request) {
        HttpServletRequest req = (HttpServletRequest) request;
        String authorization = req.getHeader(JwtHelper.AUTH_HEADER_NAME);
        if (!Strings.isNullOrEmpty(authorization)) {
            return authorization;
        }
        authorization = HttpUtil.getCookieValue(JwtHelper.AUTH_COOKIE_NAME);
        if (!Strings.isNullOrEmpty(authorization)) {
            return authorization;
        }
        return null;
    }

    /**
     * 生成签名
     */
    public static String sign(String loginName, Long tokenVersion, String role, String secret, int expireOfMinutes) {

        DateTime now = DateTime.now();

        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            return JWT.create()
                    .withHeader(HEADER)
                    .withClaim(AGENT_ID, loginName)
                    .withClaim(TOKEN_VERSION, tokenVersion)
                    .withClaim(ROLE, role)
                    .withIssuedAt(now.toDate())
                    .withExpiresAt(now.plusMinutes(expireOfMinutes).toDate())
                    .sign(algorithm);

        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        String secret = "jzt600998";
        String role = "custom";
        String token = sign("admin", 1L, role, secret, 6 * 30 * 24 * 60);
        System.out.println("token=" + token);
        System.out.println("getLoginName=" + getLoginName(token));
        System.out.println("getTokenVersion=" + getTokenVersion(token));
        System.out.println("getRole=" + getRole(token));
        System.out.println("verify(token)=" + verify(token, secret));
        System.out.println("verify(token, errorSecret)=" + verify(token, secret + "a"));
        System.out.println("verify(token, errorVersion)=" + verify(token, "admin", 0L, secret));
        System.out.println("verify(token, right)=" + verify(token, "admin", 1L, secret));
    }
}
